package org.jfonia.connect5.collections;

import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import org.jfonia.connect5.basics.BasicNode;
import org.jfonia.connect5.basics.Observer;
import org.jfonia.connect5.basics.ValueNode;

/**
 * @author wijnand.schepens@hogent.be
 */
public class SetNode<T> implements Set<T>
{
	protected Set<T> set;

	protected ElementNode additionNode;
	protected ElementNode removalNode;

	public SetNode(Set<T> set)
	{
		this.set = set;
		this.additionNode = new ElementNode();
		this.removalNode = new ElementNode();
	}

	public int size()
	{
		return set.size();
	}

	public boolean isEmpty()
	{
		return set.isEmpty();
	}

	public boolean contains(Object o)
	{
		return set.contains(o);
	}

	public Iterator<T> iterator()
	{
		return set.iterator();
	}

	public Object[] toArray()
	{
		return set.toArray();
	}

	public <T> T[] toArray(T[] a)
	{
		return set.toArray(a);
	}

	public boolean add(T e)
	{
		if (set.add(e)) {
			additionNode.setValue(e);
			return true;
		}
		else
			return false;
	}

	public boolean add(T e, Observer source)
	{
		if (set.add(e))
		{
			additionNode.setValue(e, source);
			return true;
		}
		else
			return false;
	}

	public boolean remove(Object o)
	{
		if (set.remove(o))
		{
			removalNode.setValue((T)o);
			return true;
		}
		else
			return false;
	}

	public boolean remove(Object o, Observer source)
	{
		if (set.remove(o))
		{
			removalNode.setValue((T)o, source);
			return true;
		}
		else
			return false;
	}


	public boolean containsAll(Collection<?> c)
	{
		return set.containsAll(c);
	}

	public boolean addAll(Collection<? extends T> c)
	{
		throw new UnsupportedOperationException("Not supported yet.");
	}

	public boolean retainAll(Collection<?> c)
	{
		throw new UnsupportedOperationException("Not supported yet.");
	}

	public boolean removeAll(Collection<?> c)
	{
		throw new UnsupportedOperationException("Not supported yet.");
	}

	public void clear()
	{
		while (!set.isEmpty())
			remove(set.iterator().next());
	}

	public void clear(Observer source)
	{
		while (!set.isEmpty())
			remove(set.iterator().next(), source);
	}


	public ValueNode<T> getAdditionNode()
	{
		return additionNode;
	}

	public ValueNode<T> getRemovalNode()
	{
		return removalNode;
	}





	class ElementNode extends BasicNode implements ValueNode<T>
	{
		T value;

		public T getValue()
		{
			return value;
		}

		void setValue(T value)
		{
			this.value = value;
			notifyObservers();
		}

		void setValue(T value, Observer source)
		{
			this.value = value;
			notifyObserversExcept(source);
		}
	}
}
